package c2.cross.business.championrace.sub;

import c2.cross.business.base.CrossSubModule;
import c2.cross.business.championrace.ChampionRaceModule;
import cate.common.table.d.GDChampionRace;
import cate.common.util.GameResult;
import cate.game.framework.common.compress.CompressedContent;
import cate.game.framework.common.compress.PlaySideCompressHelper;
import cate.game.play.part.PlaySide;
import cate.game.pvp.championrace.data.ChampionRaceMsg;
import cate.game.pvp.championrace.GameChampionRaceMsgManager;
import cate.game.pvp.championrace.data.ChampionRaceRank;
import cate.game.pvp.championrace.data.*;
import cate.game.pvp.championrace.dto.*;
import cate.game.role.RoleSnapshot;
import cate.game.role.pvp.championrace.msg.*;
import cate.game.role.pvp.championrace.vo.ChampionRaceGroupRoundVO;
import cate.game.role.pvp.championrace.vo.ChampionRaceReportVO;
import cate.game.role.pvp.championrace.vo.ChampionRaceRoundVO;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import easy.java.practice.errorcode.EcResult;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

public class ChampionRaceRecvModule extends CrossSubModule<ChampionRaceModule> {


    @Override
    public void initDependent() throws Exception {
        useRpcRecv().onRequestResponseTemplate(ChampionRaceMsg.GET_RANK_DATA, String.class,
                (h, req) -> this.getRankData(req));
        useRpcRecv().onRequestResponseTemplate(ChampionRaceMsg.GET_RANK_LIST, Void.class,
                (h , req) -> this.getRankList());
        useRpcRecv().onRequestResponseTemplate(ChampionRaceMsg.ADMIRE_REQ, GameChampionRaceMsgManager.AdmireParam.class,
                (h, req) -> this.handleAdmire(req));
        useRpcRecv().onRequestResponseTemplate(ChampionRaceMsg.GET_BET_ROUND_REQ, ChampionRaceBetRoundReq.class,
                (h, req) -> this.handleBetRoundReq(req));
        useRpcRecv().onRequestResponseTemplate(ChampionRaceMsg.GET_BET_ROUND_REPORT_REQ, ChampionRaceBetRoundReportReq.class,
                (h, req) -> this.handleBetRoundReportReq(req));
        useRpcRecv().onRequestResponseTemplate(ChampionRaceMsg.GET_ROUND_REQ, GameChampionRaceMsgManager.RoundReqParam.class,
                (h, req) -> this.handleRoundReq(req.getUid(), req.getReq()));
        useRpcRecv().onRequestResponseTemplate(ChampionRaceMsg.GET_ROUND_REPORT_REQ, GameChampionRaceMsgManager.RoundReportReqParam.class,
                (h, req) -> this.handleRoundReportReq(req.getUid(), req.getReq()));
        useRpcRecv().onRequestResponseTemplate(ChampionRaceMsg.GET_GROUP_ROUND_REQ, ChampionRaceGroupRoundReq.class,
                (h, req) -> this.handleGroupRoundReq(req));
        useRpcRecv().onRequestResponseTemplate(ChampionRaceMsg.GET_GROUP_ROUND_REPORT_REQ, ChampionRaceGroupRoundReportReq.class,
                (h, req) -> this.handleGroupRoundReportReq(req));
        useRpcRecv().onRequestResponseTemplate(ChampionRaceMsg.GET_PS_REQ, ChampionRaceGetPsReq.class,
                (h, req) -> this.handleGetPsReq(req));
        useRpcRecv().onRequestResponseTemplate(ChampionRaceMsg.GET_PS_MANY, Integer.class,
                (h, req) -> this.handleQueryPs(req));
        useRpcRecv().onRequestResponseTemplate(ChampionRaceMsg.BET_REQ, GameChampionRaceMsgManager.BetParam.class,
                (h, req) -> this.handleBetReq(req.getSpec(), req.getReq()));
        useRpcRecv().onRequestResponseTemplate(ChampionRaceMsg.GET_BET_RECORD, ChampionRaceSpec.class,
                (h, req) -> this.handleGetBetRecord(req));
        useRpcRecv().onRequestResponseTemplate(ChampionRaceMsg.GET_RED_PACKET, GameChampionRaceMsgManager.GetRedPacketParam.class,
                (h, req) -> this.handleGetRedPacket(req.getSnapshot(), req.getSpec()));
        useRpcRecv().onRequestResponseTemplate(ChampionRaceMsg.GET_ROLE_RED_PACKET, GameChampionRaceMsgManager.QueryRedPacketParam.class,
                (h, req) -> this.handleGetRoleRedPacket(req.getSpec(), req.getUid()));
        useRpcRecv().onRequestResponseTemplate(ChampionRaceMsg.HAS_RECVD_RED_PACKET, GameChampionRaceMsgManager.QueryRedPacketParam.class,
                (h, req) -> this.hasRecvdRedPacket(req.getSpec(), req.getUid()));
        useRpcRecv().onRequestResponseTemplate(ChampionRaceMsg.GET_RANK_REWARD, GameChampionRaceMsgManager.QueryParam.class,
                (h, req) -> this.handleRankRwd(req));
        useRpcRecv().onFireAndForgetTemplate(ChampionRaceMsg.UPDATE_PS, GameChampionRaceMsgManager.UpdatePsParam.class,
                (h, req) -> this.handleUpdatePs(req.getEps()));
        useRpcRecv().onRequestResponseTemplate(ChampionRaceMsg.GET_BET_RECORD_ALL, Void.class,
                (h, req) -> this.handleGetBetRecordAll());
        useRpcRecv().onRequestResponseTemplate(ChampionRaceMsg.GET_SPEC_PLAYERS, GameChampionRaceMsgManager.QuerySpecPlaysParam.class,
                (h, req) -> this.handleQuerySpecPlayers(req));
        useRpcRecv().onRequestResponseTemplate(ChampionRaceMsg.GET_TIMER_EVENT, ChampionRaceSpec.class,
                (h,req) -> this.handleQuerySpecTimerEvent(req));
    }

    private ChampionRaceBetRecord handleBetReq(ChampionRaceSpec redPacketSpec, ChampionRaceBetReq req) {
        if (!parent.hasRecvdRedPacket(redPacketSpec, req.uid)) {
            return null;
        }
        ChampionRaceSpec spec = ChampionRaceSpec.ofNullStep(redPacketSpec);
        List<ChampionRaceRecord> queryList = parent.queryRecords(spec);
        if (CollectionUtils.isNotEmpty(queryList)) {
            ChampionRaceBetRecord betRecord = parent.queryBetRecord(spec);
            if (Objects.nonNull(betRecord)) {
                ChampionRaceRecord record = queryList.stream()
                        .filter(rd -> rd.getSpec().getPeriod() == spec.getPeriod()
                                && rd.getSpec().getRound() == spec.getRound())
                        .findFirst()
                        .orElse(null);
                if (Objects.nonNull(record)) {
                    parent.bet(spec, req.side, GDChampionRace.FIXED_BET_NUM);
                }
            }
            return betRecord;
        }
        return null;
    }

    private ChampionRaceManyPsData handleQueryPs(int srvId) {
        ChampionRaceManyPsData data = new ChampionRaceManyPsData();
        data.setList(new ArrayList<>());
        if (srvId >= 0) {
            data.getList().addAll(parent.findPs(srvId));
        }
        return data;
    }

    private ChampionRaceGetPsResp handleGetPsReq(ChampionRaceGetPsReq req) {
        if (StringUtils.isNotBlank(req.roleUid)) {
            ChampionRacePs ps = parent.findPs(req.roleUid);
            if (Objects.nonNull(ps)) {
                CompressedContent last = ps.getCpsList().getLast();
                EcResult<PlaySide> pr = PlaySideCompressHelper.uncompressEc(last);
                if (pr.ok()) {
                    return new ChampionRaceGetPsResp(pr.data);
                }
            }
        }
        return null;
    }

    private ChampionRaceGroupRoundReportResp handleGroupRoundReportReq(ChampionRaceGroupRoundReportReq req) {
        if (Objects.nonNull(req.to) && (Objects.isNull(req.from) || req.from.getGroup() == req.to.getGroup())) {
            List<ChampionRaceRecord> queryList = parent.queryRecords(req.from, req.to);
            if (CollectionUtils.isNotEmpty(queryList)) {
                Map<String, List<ChampionRaceReportVO>> reportMap = queryList.stream()
                        .filter(rd -> rd.getSpec().getGroup() == req.to.getGroup())
                        .collect(Collectors.groupingBy(e -> e.getSpec().toString(), Collectors.mapping(ChampionRaceReportVO::of, Collectors.toList())));
                return new ChampionRaceGroupRoundReportResp(req.tag, reportMap);
            }
        }
        return null;
    }

    private ChampionRaceGroupRoundResp handleGroupRoundReq(ChampionRaceGroupRoundReq req) {
        if (Objects.nonNull(req.to) && (Objects.isNull(req.from) || req.from.getGroup() == req.to.getGroup())) {
            List<ChampionRaceRecord> queryList = parent.queryRecords(req.from, req.to);
            if (CollectionUtils.isNotEmpty(queryList)) {
                Map<String, List<ChampionRaceGroupRoundVO>> roundMap = queryList.stream()
                        .filter(rd -> rd.getSpec().getGroup() == req.to.getGroup())
                        .collect(Collectors.groupingBy(rd -> rd.getSpec().toString(), Collectors.mapping(this::transGroupRoundVO, Collectors.toList())));
                return new ChampionRaceGroupRoundResp(req.tag, roundMap);
            }
        }
        return null;
    }

    private ChampionRaceGroupRoundVO transGroupRoundVO(ChampionRaceRecord record) {
        ChampionRacePs epsA = null, epsB = null;
        if (StringUtils.isNotBlank(record.getIdA())) {
            epsA = parent.findPs(record.getIdA());
        }
        if (StringUtils.isNotBlank(record.getIdB())) {
            epsB = parent.findPs(record.getIdB());
        }
        RoleSnapshot snapshotA = null, snapshotB = null;
        if (Objects.nonNull(epsA)) {
            CompressedContent cc = epsA.getCpsList().get(record.getPsA());
            EcResult<PlaySide> r = PlaySideCompressHelper.uncompressEc(cc);
            if (r.ok()) {
                snapshotA = r.data.snapshot.copy();
            }
        }
        if (Objects.nonNull(epsB)) {
            CompressedContent cc = epsB.getCpsList().get(record.getPsB());
            EcResult<PlaySide> r = PlaySideCompressHelper.uncompressEc(cc);
            if (r.ok()) {
                snapshotB = r.data.snapshot.copy();
            }
        }
        return ChampionRaceGroupRoundVO.of(
                record.getRid(),
                record.getIndex(),
                snapshotA,
                snapshotB);
    }

    private ChampionRaceRoundReportResp handleRoundReportReq(String uid, ChampionRaceRoundReportReq req) {
        ChampionRaceRoundReportResp resp = new ChampionRaceRoundReportResp();
        List<ChampionRaceRecord> queryList = parent.queryRecords(uid, req.from, req.to);
        if (CollectionUtils.isNotEmpty(queryList)) {
            resp.reportMap = queryList.stream().collect(Collectors.toMap(e -> e.getSpec().toString(), ChampionRaceReportVO::of));
        }
        return resp;
    }

    private ChampionRaceRoundResp handleRoundReq(String uid, ChampionRaceRoundReq req) {
        ChampionRaceRoundResp resp = new ChampionRaceRoundResp();
        List<ChampionRaceRecord> queryList = parent.queryRecords(uid, req.from, req.to);
        if (CollectionUtils.isNotEmpty(queryList)) {
            resp.roundMap = queryList.stream().collect(Collectors.toMap(e -> e.getSpec().toString(), this::transRoundVO));
        }
        return resp;
    }

    private ChampionRaceBetRoundReportResp handleBetRoundReportReq(ChampionRaceBetRoundReportReq req) {
        List<ChampionRaceRecord> queryList = parent.queryRecords(req.from, req.to);
        if (CollectionUtils.isNotEmpty(queryList)) {
            Map<String, ChampionRaceReportVO> reports = queryList.stream()
                    .filter(ChampionRaceRecord::isBetRound)
                    .collect(Collectors.toMap(e -> e.getSpec().toString(), ChampionRaceReportVO::of));
            return new ChampionRaceBetRoundReportResp(reports);
        }
        return null;
    }

    private ChampionRaceBetRoundResp handleBetRoundReq(ChampionRaceBetRoundReq req) {
        Map<String, ChampionRaceRoundVO> map = new HashMap<>();
        List<ChampionRaceRecord> queryList = parent.queryRecords(req.from, req.to);
        if (CollectionUtils.isNotEmpty(queryList)) {
            map = queryList.stream()
                    .filter(ChampionRaceRecord::isBetRound)
                    .collect(Collectors.toMap(e -> e.getSpec().toString(), this::transRoundVO));
        }
        return new ChampionRaceBetRoundResp(map);
    }

    private ChampionRaceRoundVO transRoundVO(ChampionRaceRecord record) {
        ChampionRacePs epsA = null, epsB = null;
        if (StringUtils.isNotBlank(record.getIdA())) {
            epsA = parent.findPs(record.getIdA());
        }
        if (StringUtils.isNotBlank(record.getIdB())) {
            epsB = parent.findPs(record.getIdB());
        }
        PlaySide psA = null, psB = null;
        if (Objects.nonNull(epsA)) {
            CompressedContent cc = epsA.getCpsList().get(record.getPsA());
            EcResult<PlaySide> r = PlaySideCompressHelper.uncompressEc(cc);
            if (r.ok()) {
                psA = r.data;
            }
        }
        if (Objects.nonNull(epsB)) {
            CompressedContent cc = epsB.getCpsList().get(record.getPsB());
            EcResult<PlaySide> r = PlaySideCompressHelper.uncompressEc(cc);
            if (r.ok()) {
                psB = r.data;
            }
        }
        return ChampionRaceRoundVO.of(record.getRid(), record.getIndex(), psA, psB);
    }

    public ChampionRaceRank getRankData(String roleUid) {
        return parent.getRankData(roleUid);
    }

    public ChampionRaceRankListData getRankList() {
        ChampionRaceRankListData data = new ChampionRaceRankListData();
        data.list = parent.getRankList();
        return data;
    }

    public ChampionRaceBetRecord handleGetBetRecord(ChampionRaceSpec spec) {
        return parent.queryBetRecord(spec);
    }

    public ChampionRaceRedPacketResp handleGetRedPacket(RoleSnapshot snapshot, ChampionRaceSpec spec) {
        List<ChampionRaceRedPacketRecord> list = parent.getRedPacket(spec, snapshot);
        ChampionRaceRedPacketResp resp = new ChampionRaceRedPacketResp();
        resp.rdList = list;
        return resp;
    }

    public ChampionRaceRedPacketResp handleGetRoleRedPacket(ChampionRaceSpec spec, String roleUid) {
        List<ChampionRaceRedPacketRecord> list = parent.getRoleRedPacket(spec, roleUid);
        ChampionRaceRedPacketResp resp = new ChampionRaceRedPacketResp();
        resp.rdList = list;
        return resp;
    }

    public boolean hasRecvdRedPacket(ChampionRaceSpec spec, String roleUid) {
        return parent.hasRecvdRedPacket(spec, roleUid);
    }

    public ChampionRaceRankRewardData handleRankRwd(GameChampionRaceMsgManager.QueryParam param) {
        ChampionRaceRankRewardData data = new ChampionRaceRankRewardData();
        data.list = parent.getRankRwdList(param.getSeason(), param.getSrvId());
        return data;
    }

    public void handleUpdatePs(ChampionRacePs ps) {
        if (Objects.isNull(ps)) {
            return ;
        }
        parent.updatePs(ps);
    }

    public ChampionRaceAllBetRecordsData handleGetBetRecordAll() {
        List<ChampionRaceBetRecord> records = parent.getAllBetRecord();
        ChampionRaceAllBetRecordsData data = new ChampionRaceAllBetRecordsData();
        data.records = records;
        return data;
    }

    public ChampionRaceSpecPlayersData handleQuerySpecPlayers(GameChampionRaceMsgManager.QuerySpecPlaysParam req) {
        ChampionRaceSpecPlayersData data = new ChampionRaceSpecPlayersData();
        List<ChampionRaceRecord> queryList;
        ChampionRaceSpec spec = req.getSpec();
        int srvId = req.getSrvId();
        if (spec.getPeriod() == (byte) 2) {
            queryList = Lists.newArrayList();
            for (int i = 0; i < 8; i++) {
                ChampionRaceSpec querySpec = ChampionRaceSpec.of(
                        spec.getSeason(),
                        spec.getPeriod(),
                        (byte) i,
                        spec.getRound(),
                        spec.getStep());
                List<ChampionRaceRecord> recordList = parent.queryRecords(querySpec);
                if (!CollectionUtils.isEmpty(recordList)) {
                    queryList.addAll(recordList);
                }
            }
        } else {
            queryList = parent.queryRecords(spec);
        }
        if (CollectionUtils.isEmpty(queryList)) {
            return data;
        }
        Map<String, String> players = Maps.newHashMap();
        for (ChampionRaceRecord record : queryList) {
            if (StringUtils.isNotBlank(record.getIdA())) {
                ChampionRacePs psA = parent.findPs(record.getIdA());
                if (Objects.nonNull(psA) && psA.getOpponent().getSnapshot().base.srvId == srvId) {
                    players.put(record.getIdA(), psA.getCpsList().getLast().getMd5Sum());
                }
            }
            if (StringUtils.isNotBlank(record.getIdB())) {
                ChampionRacePs psB = parent.findPs(record.getIdB());
                if (Objects.nonNull(psB) && psB.getOpponent().getSnapshot().base.srvId == srvId) {
                    players.put(record.getIdB(), psB.getCpsList().getLast().getMd5Sum());
                }
            }
        }
        data.players = players;
        return data;
    }

    public GameResult<Void> handleAdmire(GameChampionRaceMsgManager.AdmireParam req) {
        return parent.admire(req.getIndex(), req.getUid());
    }

    public ChampionRaceTimerEventData handleQuerySpecTimerEvent(ChampionRaceSpec spec) {
        ChampionRaceTimerEventData data = new ChampionRaceTimerEventData();
        if (spec == null) {
            return data;
        }
        data.events = parent.getSpecTimerEvents(spec);
        data.spec = parent.getSpec();
        data.openTime = parent.getOpenTime();
        data.closeTime = parent.getCloseTime();
        data.attributes = parent.getAttributes();
        return data;
    }
}
